//
//  PSLinkedListTests.m
//  PrefCore
//
//  Created by Sergey on 5/6/14.
//  Copyright (c) 2014 Play-on-smart. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "PSLinkedList.h"
#import "PSNamedLinkedElement.h"

@interface PSLinkedListTests : XCTestCase

@end

@implementation PSLinkedListTests

- (void)setUp {
    [super setUp];
    XCTAssertEqual(0, [PSNamedLinkedElement totalCount]);
}

-(void)tearDown {
    XCTAssertEqual(0, [PSNamedLinkedElement totalCount]);
}

- (void)testCreate {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    XCTAssertNotNil(list);
    XCTAssertEqual(0, [PSNamedLinkedElement totalCount]);
}

-(void)testClear {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:@"quick"]];
    XCTAssertEqual(1, [PSNamedLinkedElement totalCount]);
    [list addLast:[PSNamedLinkedElement entryWithName:@"brown"]];
    XCTAssertEqual(2, [PSNamedLinkedElement totalCount]);
    [list addLast:[PSNamedLinkedElement entryWithName:@"fox"]];
    XCTAssertEqual(3, [PSNamedLinkedElement totalCount]);
    XCTAssertEqual(3, list.count);
    [list clear];
    XCTAssertEqual(0, list.count);
}

-(void)testAddFirst {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addFirst:[PSNamedLinkedElement entryWithName:@"quick"]];
    [list addFirst:[PSNamedLinkedElement entryWithName:@"brown"]];
    [list addFirst:[PSNamedLinkedElement entryWithName:@"fox"]];
    XCTAssertEqualObjects(@"{fox, brown, quick}", [list description]);
}

-(void)testAddLast {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:@"quick"]];
    [list addLast:[PSNamedLinkedElement entryWithName:@"brown"]];
    [list addLast:[PSNamedLinkedElement entryWithName:@"fox"]];
    XCTAssertEqualObjects(@"{quick, brown, fox}", [list description]);
}

-(void)testRemoveFirst {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:@"quick"]];
    [list addLast:[PSNamedLinkedElement entryWithName:@"brown"]];
    [list addLast:[PSNamedLinkedElement entryWithName:@"fox"]];
    [list removeFirst];
    XCTAssertEqualObjects(@"{brown, fox}", [list description]);
    [list removeFirst];
    XCTAssertEqualObjects(@"{fox}", [list description]);
    [list removeFirst];
    XCTAssertEqualObjects(@"{}", [list description]);
}

-(void)testRemoveLast {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:@"quick"]];
    [list addLast:[PSNamedLinkedElement entryWithName:@"brown"]];
    [list addLast:[PSNamedLinkedElement entryWithName:@"fox"]];
    [list removeLast];
    XCTAssertEqualObjects(@"{quick, brown}", [list description]);
    [list removeLast];
    XCTAssertEqualObjects(@"{quick}", [list description]);
    [list removeLast];
    XCTAssertEqualObjects(@"{}", [list description]);
}

-(void)testRemoveSpecific {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    __unsafe_unretained PSNamedLinkedElement *a;
    [list addLast:a=[PSNamedLinkedElement entryWithName:@"quick"]];
    __unsafe_unretained PSNamedLinkedElement *b;
    [list addLast:b=[PSNamedLinkedElement entryWithName:@"brown"]];
    __unsafe_unretained PSNamedLinkedElement *c;
    [list addLast:c=[PSNamedLinkedElement entryWithName:@"fox"]];
    // Move the iterator to the middle entry
    [list start];
    [list nextEntry];
    [list nextEntry];
    XCTAssertEqual(3, [PSNamedLinkedElement totalCount]);
    [list remove:a];
    XCTAssertEqualObjects(@"{brown, fox}", [list description]);
    [list remove:c];
    XCTAssertEqualObjects(@"{brown}", [list description]);
    [list remove:b];
    XCTAssertEqualObjects(@"{}", [list description]);
}

-(void)testFirst {
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:@"quick"]];
    PSNamedLinkedElement *first = list.first;
    XCTAssertEqualObjects(@"quick", first.name);
    [list addLast:[PSNamedLinkedElement entryWithName:@"brown"]];
    first = list.first;
    XCTAssertEqualObjects(@"quick", first.name);
    [list addLast:[PSNamedLinkedElement entryWithName:@"fox"]];
    first = list.first;
    XCTAssertEqualObjects(@"quick", first.name);
    first = nil;
    list = nil;
}

-(void)testIteration {
    NSArray *items = @[@"quick", @"brown", @"fox"];
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:items[0]]];
    [list addLast:[PSNamedLinkedElement entryWithName:items[1]]];
    [list addLast:[PSNamedLinkedElement entryWithName:items[2]]];
    int count = 0;
    [list start];
    while (list.hasNextEntry && count != 2) {
        PSNamedLinkedElement *tmp = list.nextEntry;
        XCTAssertEqualObjects(items[count], tmp.name);
        count++;
    }
    XCTAssertEqual(2, count);
    // Restat iterations
    [list start];
    count = 0;
    while (list.hasNextEntry) {
        PSNamedLinkedElement *tmp = list.nextEntry;
        XCTAssertEqualObjects(items[count], tmp.name);
        count++;
    }
    XCTAssertEqual(3, count);
}

-(void)testRemoveWhileIterating {
    NSArray *items = @[@"quick", @"brown", @"fox"];
    PSLinkedList *list = [[PSLinkedList alloc] init];
    [list addLast:[PSNamedLinkedElement entryWithName:items[0]]];
    [list addLast:[PSNamedLinkedElement entryWithName:items[1]]];
    [list addLast:[PSNamedLinkedElement entryWithName:items[2]]];
    int count = 0;
    [list start];
    while (list.hasNextEntry) {
        PSNamedLinkedElement *tmp = list.nextEntry;
        XCTAssertEqualObjects(items[count], tmp.name);
        count++;
        [list removeCurrentEntry];
    }
    XCTAssertEqual(3, count);
}

-(void)testMoveAppend {
    NSArray *items = @[@"quick", @"brown", @"fox", @"jumps", @"over", @"the", @"lazy", @"dog"];
    PSLinkedList *one = [[PSLinkedList alloc] init];
    [one addLast:[PSNamedLinkedElement entryWithName:items[0]]];
    [one addLast:[PSNamedLinkedElement entryWithName:items[1]]];
    [one addLast:[PSNamedLinkedElement entryWithName:items[2]]];
    PSLinkedList *two = [[PSLinkedList alloc] init];
    [two addLast:[PSNamedLinkedElement entryWithName:items[3]]];
    [two addLast:[PSNamedLinkedElement entryWithName:items[4]]];
    [two addLast:[PSNamedLinkedElement entryWithName:items[5]]];
    [two addLast:[PSNamedLinkedElement entryWithName:items[6]]];
    [two addLast:[PSNamedLinkedElement entryWithName:items[7]]];
    XCTAssertEqual(3, one.count);
    XCTAssertEqualObjects(@"{quick, brown, fox}", [one description]);
    XCTAssertEqual(5, two.count);
    XCTAssertEqualObjects(@"{jumps, over, the, lazy, dog}", [two description]);
    [one moveAppend:two];
    XCTAssertEqual(8, one.count);
    XCTAssertEqualObjects(@"{quick, brown, fox, jumps, over, the, lazy, dog}", [one description]);
    XCTAssertEqual(0, two.count);
    XCTAssertEqualObjects(@"{}", [two description]);
}

@end
